home *** CD-ROM | disk | FTP | other *** search
/ Almathera Ten Pack 3: CDPD 3 / Almathera Ten on Ten - Disc 3: CDPD3.iso / scope / 101-125 / scopedisk106 / bbs-index / src / bbsindex.c < prev    next >
Encoding:
C/C++ Source or Header  |  1995-03-19  |  17.7 KB  |  566 lines

  1. /*
  2.  * BBSindex                         (C) Copyright Eddy Carroll, August 1989
  3.  *
  4.  * This is a utility which will scan the file catalogue of BBS-PC! and
  5.  * build lists of the files in various sections and directories.
  6.  *
  7.  * It is designed to be run automatically on a regular basis in the
  8.  * background. It reads in instructions from an input file, and 
  9.  * produces output files based on these instructions.
  10.  *
  11.  * Usage: BBSindex [options] [scriptfile] ..
  12.  *
  13.  * With no parameters, a short help message is displayed.
  14.  *
  15.  * The possible options are:
  16.  *
  17.  * -c <file>        This specifies the configuration file (CFGINFO.DAT)
  18.  * -d <file>           This specifies the input file (default UDHEAD.DAT)
  19.  * -f "string"                 This specifies the format string for the output
  20.  * -h                          Displays the help message
  21.  * -n                          Stops AmigaDOS putting up requesters
  22.  * -t               Trace mode - display each line before execution
  23.  *
  24.  * scriptfile is a file containing commands to control what is output.
  25.  * See the documentation for more info. Note that options and script files
  26.  * may be freely interspersed.
  27.  *
  28.  */
  29.  
  30. #define MAIN
  31.  
  32. #ifndef LATTICE_50
  33. #include "system.h"
  34. #endif
  35.  
  36. #include "bbsindex.h"
  37.  
  38. /*
  39.  *             Miscellaneous static global variables
  40.  */
  41.  
  42. static struct IntuitionBase *IntuitionBase;
  43. static BPTR infile, lock;
  44. static struct Remember *memkey;
  45. static char buffer[BUFSIZE];
  46. static int bufpos = 0;
  47. static APTR requeststat;       /* Ptr to window for AmigaDos requesters */
  48.  
  49. /*
  50.  *             print()
  51.  *             -------
  52.  *             Prints a string to standard output
  53.  */
  54. void print(s)
  55. char *s;
  56. {
  57.        Write(errorfile,s,strlen(s));
  58. }
  59.  
  60. /*
  61.  *             Cleanup()
  62.  *             ---------
  63.  *             Releases all program resources, and exits. Note that because of
  64.  *             the way it checks to see if a resource is allocated, you need to
  65.  *             set pointers to NULL if you release the object associated with
  66.  *             them. For example, when you close a file, remember to set the
  67.  *             file handle to NULL immediately afterwards, otherwise Cleanup()
  68.  *             will try to close it again.
  69.  */
  70. void Cleanup(code)
  71. int code;
  72. {
  73.        static ctrlc;
  74.        struct Process *me = (struct Process *)FindTask(0L);
  75.        int i;
  76.  
  77.        if (!ctrlc) {
  78.                ctrlc = 1;
  79.                me->pr_WindowPtr = requeststat;
  80.                if (script)
  81.                        FreeMem(script, scriptsize);
  82.                for (i = 0; i < nummacros; i++)
  83.                        FreeMem(macros[i], MACROSIZE + macros[i]->size);
  84.                for (i = 0; i < nestlevel; i++)
  85.                        FreeMem(params[i], PARAMSIZE + params[i]->size);
  86.                if (memkey)
  87.                        FreeRemember(&memkey, TRUE);
  88.                if (IntuitionBase)
  89.                        CloseLibrary(IntuitionBase);
  90.                if (lock)
  91.                        UnLock(lock);
  92.                if (dirlock)
  93.                        UnLock(dirlock);
  94.                if (infile)
  95.                        Close(infile);
  96.                if (outfile != Output())
  97.                        Close(outfile);
  98.                if (errorfile)
  99.                        Close(errorfile);
  100.                exit(code);
  101.        }
  102. }
  103.  
  104. /*
  105.  *             cxovf()
  106.  *             -------
  107.  *             The standard lattice "stack abort" code. This is called when the
  108.  *             stack overflows (having first reset the stack pointer to something
  109.  *             safe of course).
  110.  */
  111. void cxovf()
  112. {
  113.        print("\nBBSindex: Stack overflow! Use the STACK command "
  114.                  "to increase stack size\n");
  115.        Cleanup(32);
  116. }
  117.  
  118. /*
  119.  *             chkabort()
  120.  *             ----------
  121.  *             My own version of chkabort(), called by the Lattice Library
  122.  *             functions periodically to check for CTRL-C.
  123.  *
  124.  *             This version cleans up first (otherwise, after CTRL-C'ing a few times
  125.  *             while  processing a 220K UDHEAD.DAT file, you find you don't have any
  126.  *             memory left!).
  127.  */
  128. void chkabort()
  129. {
  130.        if (SetSignal(0,0) & SIGBREAKF_CTRL_C) {
  131.                SetSignal(0,0xffffffff);
  132.                print("^C\n");
  133.                Cleanup(5);
  134.        }
  135. }
  136.  
  137.  
  138. /*
  139.  *             SafeAllocMem()
  140.  *             --------------
  141.  *             A revised AllocMem() that checks for out of memory.
  142.  */
  143. void *SafeAllocMem(size)
  144. int size;
  145. {
  146.        void *ptr = AllocMem(size, 0);
  147.        if (!ptr) {
  148.                print("BBSindex: Out of memory!\n");
  149.                Cleanup(20);
  150.        }
  151.        return (ptr);
  152. }
  153.  
  154.  
  155. /*
  156.  *             mymalloc()
  157.  *             ----------
  158.  *             My own private malloc. No memory limits, and no library overhead.
  159.  *             Easy to replace the call to AllocRemember with one to malloc for
  160.  *             portability. To try and keep down memory fragmentation, requests
  161.  *             for memory less than 200 bytes are allocated from a larger block
  162.  *             which is allocated "on the fly".
  163.  */
  164. void *mymalloc(size)
  165. int size;
  166. {
  167.        static void *bigblock;                          /* Current large memory block */
  168.        static int curpos = FRAGBLOCK;          /* Current position in block  */
  169.        void *ptr;
  170.        
  171.        size = (size + 7) & 0xfffffff8;         /* Round up to 8 block boundary */
  172.        if (size < FRAGTHRESH) {
  173.                /*
  174.                 *              If we want a small chunk, allocate it from our intermediate
  175.                 *              block.
  176.                 */
  177.                if ((size + curpos) > FRAGBLOCK) {
  178.                        bigblock = mymalloc(FRAGBLOCK);
  179.                        curpos = 0;
  180.                }
  181.                ptr = (char *)bigblock + curpos;
  182.                curpos += size;
  183.        } else {
  184.                /*
  185.                 *              Otherwise, just allocate memory as normal.
  186.                 */
  187.                ptr = AllocRemember(&memkey, size, 0);
  188.                if (!ptr) {
  189.                        print("BBSindex: Out of memory!\n");
  190.                        Cleanup(20);
  191.                }
  192.        }
  193.        return (ptr);
  194. }
  195.  
  196.  
  197. /*
  198.  *             dumpdata()
  199.  *             ----------
  200.  *             Outputs raw data to a file, checking for write errors.
  201.  */
  202. void dumpdata(buf,len)
  203. char *buf;
  204. int len;
  205. {
  206.        if (Write(outfile, buf, len) != len) {
  207.                print("BBSindex: Error writing output file (disk full?)\n");
  208.                Cleanup(10);
  209.        }
  210. }
  211.  
  212. /*
  213.  *             putstring()
  214.  *             -----------
  215.  *             This function outputs a string to the current output file. If the
  216.  *             file is a tty, the string is output immediately, else it is
  217.  *             buffered up and output when it is big enough.
  218.  */
  219.  
  220. void putstring(s)
  221. char *s;
  222. {
  223.        int len = strlen(s);
  224.  
  225.        if (toscreen) {
  226.                dumpdata(s, len);
  227.        } else {
  228.                if ( (bufpos + len) > BUFSIZE) {
  229.                        dumpdata(buffer, bufpos);
  230.                        bufpos = 0;
  231.                }
  232.                strcpy(buffer+bufpos, s);
  233.                bufpos += len;
  234.        }
  235. }
  236.  
  237. /*
  238.  *             flushout()
  239.  *             ----------
  240.  *             Flushes output to disk, before closing a file.
  241.  */
  242.  
  243. void flushout()
  244. {
  245.        if (bufpos > 0) {
  246.                dumpdata(buffer, bufpos);
  247.        }
  248.        bufpos = 0;
  249. }
  250.  
  251. /*
  252.  *             openfile()
  253.  *             ----------
  254.  *             Opens a specified file for reading, and returns the length
  255.  *             of the file. If an error occurs, aborts automatically. The
  256.  *             caller has responsibility for calling Close(infile) when finished
  257.  *             with the file.
  258.  */
  259. long openfile(filename)
  260. char *filename;
  261. {
  262.        if ((lock = Lock(filename, ACCESS_READ)) == NULL) {
  263.                print3("BBSindex: Can't access file ",filename,"\n");
  264.                Cleanup(5);
  265.        }
  266.  
  267.        if (!Examine(lock, fib)) {
  268.                print3("BBSindex: Can't get info for file ",filename,"\n");
  269.                Cleanup(5);
  270.        }
  271.        UnLock(lock); lock = NULL;
  272.  
  273.        if ((infile = Open(filename, MODE_OLDFILE)) == NULL) {
  274.                print3("BBSindex: Can't open file ",filename," for input\n");
  275.                Cleanup(5);
  276.        }
  277.        return (fib->fib_Size);
  278. }
  279.  
  280. /*
  281.  *             readdatabase()
  282.  *             --------------
  283.  *             This function reads in the entire file database into memory,
  284.  *             allocating memory as required. It sets up an array of pointers to
  285.  *             the records in the database, which is used by qsort() among other
  286.  *             things.
  287.  *
  288.  *             Note that the memory needed is allocated in a number of small
  289.  *             chunks each BLOCKSIZE * UDSIZE bytes in size (~16K by default).
  290.  *             This means there doesn't need to be a contigous block of memory
  291.  *             big enough to hold the whole file database available - it is
  292.  *             split into smaller chunks instead.
  293.  */
  294.  
  295. void readdatabase(filename)
  296. char *filename;
  297. {
  298.        long    size;
  299.        long    bsize;
  300.        long    i,j;
  301.        UDHEAD  *block;         /* Pointer to block of headers  */
  302.        UDHEAD  **p;
  303.  
  304.        readfiles = TRUE;
  305.  
  306.        size = openfile(filename);
  307.        if ((size % UDSIZE) || (size < (2 * UDSIZE))) {
  308.                print3("BBSindex: ",filename,
  309.                           " isn't a valid BBS-PC! file header file!\n");
  310.                Cleanup(5);
  311.        }
  312.  
  313.        /*
  314.         *              File successfully opened, now read in file data.
  315.         *              Skip past unneeded data at start of BBS-PC! file
  316.         */
  317.        Seek(infile, UDSIZE * 2, OFFSET_BEGINNING);
  318.        size            = size - (2 * UDSIZE);
  319.        numrecs         = size/UDSIZE;
  320.        ptrblock        = mymalloc(numrecs * sizeof(UDHEAD *));
  321.        p                       = ptrblock;
  322.  
  323.        /*
  324.         *      Now allocate blocks to hold data, read in data, and setup initial
  325.         *      pointers to point to the file headers.
  326.         */
  327.        for (i = numrecs; i > 0; i = i - BLOCKSIZE) {
  328.  
  329.                bsize = (i > BLOCKSIZE ? BLOCKSIZE : i);
  330.                block = mymalloc(bsize * UDSIZE);
  331.  
  332.                chkabort();
  333.                if (Read(infile, block, bsize * UDSIZE) != (bsize * UDSIZE)) {
  334.                        print3("BBSindex: Error reading from file",filename,"\n");
  335.                        Cleanup(10);
  336.                }
  337.  
  338.                /*
  339.                 *              Now initialise all the pointers for this block. Also
  340.                 *              null-terminate the catalogue filename, since BBS-PC!
  341.                 *              doesn't always save out the null termination byte.
  342.                 *              Also set Online and Valid files to 0, by default.
  343.                 *              These will be updated by CHECKFILES.
  344.                 */
  345.  
  346.                for (j = 0; j < bsize; j++) {
  347.                        block->cat_name[15] = '\0';
  348.                        block->online = 0;
  349.                        block->valid = 0;
  350.                        block->dirnum = 0;
  351.                       *p++ = block++;
  352.                }
  353.        }
  354.        Close(infile); infile = NULL;
  355. }
  356.  
  357. /*
  358.  *             readconfigfile()
  359.  *             ----------------
  360.  *             This function reads in the configuration file (i.e. CONFIG.DAT),
  361.  *             if present, and initialises the directory array with the
  362.  *             directory names. If the file isn't present, readconfig is set
  363.  *             to FALSE, so that CHECKFILES won't work unless directories are
  364.  *             specified on the command line.
  365.  */
  366. void readconfigfile()
  367. {
  368.        int i;
  369.        long size;
  370.  
  371.        size = openfile(configname);
  372.        if (size != CFGSIZE) {
  373.                print3("BBSindex: ", configname,
  374.                        " is not a valid configuration file\n");
  375.                Cleanup(10);
  376.        }
  377.        if (Read(infile, config, CFGSIZE) != CFGSIZE) {
  378.                print3("BBSindex: Error reading from configuration file ",
  379.                                configname, "\n");
  380.                Cleanup(10);
  381.        }
  382.        Close(infile);
  383.        infile = NULL;
  384.        for (i = 0; i < NUM_SECT; i++)
  385.                strcpy(dirnames[i], config->ud_alt[i]);
  386. }
  387.  
  388.  
  389. /*
  390.  *             readscript()
  391.  *             ------------
  392.  *             This function reads in the specified script file into memory.
  393.  *             It allocates memory for the script file on the fly - this 
  394.  *             memory should be released by the caller, either through calling
  395.  *             Cleanup(), or explicitly by calling FreeMem(). If the latter,
  396.  *             remember to set script = NULL immediately afterwards.
  397.  *
  398.  *             The script pointer is set to the start of the script buffer by
  399.  *             this call, so readcommand() will start at the beginning of the file.
  400.  */
  401.  
  402. void readscript(filename)
  403. char *filename;
  404. {
  405.        strcpy(scriptname, filename);
  406.        scriptsize = openfile(filename);
  407.        if (scriptsize == 0) {
  408.                print3("BBSindex: Script file ",filename," is empty.\n");
  409.                Cleanup(10);
  410.        }
  411.  
  412.        script = SafeAllocMem(scriptsize);
  413.        if (Read(infile, script, scriptsize) != scriptsize) {
  414.                print3("BBSindex: Error reading script file ", filename, "\n");
  415.                Cleanup(10);
  416.        }
  417.        Close(infile); infile = NULL;
  418.        scriptpos = 0;
  419.        linenum = 1;
  420. }
  421.  
  422. /*
  423.  *             help()
  424.  *             ------
  425.  *             Prints out a help screen for the program.
  426.  */
  427. void help()
  428. {
  429.        print("BBSindex V1.0 file utility for BBS-PC! "
  430.                  "Copyright (C) Eddy Carroll 1989.\n");
  431.        print("Usage: bbsindex {options} scriptfile ..\n\n");
  432.        print("Possible options are:\n\n");
  433.        print(" -c filename    Read configuration from filename (default ");
  434.        print2(configname, ")\n");
  435.        print(" -d filename    Read database from filename (default ");
  436.        print2(databasename, ")\n");
  437.        print(" -f \"string\"    Format output as string (default \""
  438.                  "%15n %w %-6x-%b{B,T}  %c\")\n");
  439.        print(" -h             Print this help screen\n");
  440.        print(" -n             Disable AmigaDos requesters\n");
  441.        print(" -t             Turn on trace mode\n\n");
  442.        print("(See documentation for a description of the script language.)\n");
  443.        Cleanup(5);
  444. }
  445.  
  446. /*
  447.  *             doscript()
  448.  *             ----------
  449.  *             Reads in and executes the specified script file.
  450.  */
  451. void doscript(name)
  452. char *name;
  453. {
  454.        readscript(name);
  455.        execscript();
  456.        flushout();
  457.        FreeMem(script, scriptsize);
  458.        script = NULL;
  459. }
  460.  
  461.  
  462. /*
  463.  *             Mainline
  464.  *             --------
  465.  */
  466.  
  467. void main(argc,argv)
  468. int argc;
  469. char *argv[];
  470. {
  471.        struct Process *me = (struct Process *)FindTask(0L);
  472.        requeststat = me->pr_WindowPtr;
  473.  
  474.        /*
  475.         *              Setup defaults for command line etc.
  476.         */
  477.  
  478.        errorfile       = Open("*", MODE_NEWFILE);
  479.        outfile         = Output();
  480.        toscreen        = IsInteractive(outfile);
  481.        strcpy(formatstring, FORMAT);
  482.        strcpy(databasename, UDNAME);
  483.        strcpy(configname,   CFGNAME);
  484.        tree[0].field = E_ALL;          /* By default, select all files */
  485.  
  486.  
  487.        /*
  488.         *              Open standard resources
  489.         */
  490.        if ((IntuitionBase = OpenLibrary("intuition.library",33)) == NULL) {
  491.                print("BBSindex: Couldn't open intuition.library, sigh.\n");
  492.                Cleanup(5);
  493.        }
  494.  
  495.        /*
  496.         *              Allocate space for reading directory info into
  497.         */
  498.        fib = mymalloc(sizeof(struct FileInfoBlock));
  499.  
  500.  
  501.        /*
  502.         *              Check to see were we run with the name PROGSCRIPT. Only
  503.         *              check the last part of the filename, in case we were run with
  504.         *              a full path (like BBS:BBSCRIPT for example).
  505.         */
  506.        if (!stricmp(argv[0] + strlen(argv[0]) - strlen(PROGSCRIPT), PROGSCRIPT)) {
  507.                doscript(DEFSCRIPT);
  508.                Cleanup(0);
  509.        }
  510.  
  511.        /*
  512.         *              Now parse the command line.
  513.         */
  514.        if (argc < 2) {
  515.                help();
  516.                Cleanup(0);
  517.        }
  518.  
  519.        while (argc > 1) {
  520.                if (argv[1][0] == '-') {
  521.                        switch (argv[1][1]) {
  522.  
  523.                                case 'c':                                       /* Set config filename */
  524.                                        argv++, argc--;
  525.                                        strcpy(configname, argv[1]);
  526.                                        break;
  527.  
  528.                                case 'd':                                       /* Set database filename */
  529.                                        argv++; argc--;
  530.                                        strcpy(databasename, argv[1]);
  531.                                        break;
  532.  
  533.                                case 'f':                                       /* Format string */
  534.                                        argv++; argc--;
  535.                                        strcpy(formatstring, argv[1]);
  536.                                        strcat(formatstring, "\n");
  537.                                        break;
  538.  
  539.                                case 'h':                                       /* Display help */
  540.                                        help();
  541.                                        break;
  542.  
  543.                                case 'n':                                       /* Disable AmigaDos requesters */
  544.                                        com_norequest();
  545.                                        break;
  546.  
  547.                                case 't':
  548.                                        tracemode = TRUE;
  549.                                        break;
  550.  
  551.                                default:
  552.                                        print3("BBSindex: Unknown option ", argv[1], "ignored\n");
  553.                                        break;
  554.                        }
  555.                } else          /* Not a command line option, so invoke script */
  556.                        doscript(argv[1]);
  557.                argv++, argc--;
  558.        }
  559.        Cleanup(0);
  560. }
  561.  
  562.  
  563. void __fpinit(){}
  564. void __fpterm(){}
  565. void MemCleanup(){}
  566.